<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>10 Observable Operator - combineLatest, withLatestFrom, zip · ShaofeiZi Blog · 做个日常记录</title>
    <meta name="description" content="訾绍飞的博客。万物皆有裂缝处，那是光射进来的地方。">
    <link rel="shortcut icon" href="/BLOG/favicon.ico">
  <link rel="manifest" href="/BLOG/manifest.json">
  <meta name="theme-color" content="#3F51B5">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <link rel="apple-touch-icon" href="/BLOG/icons/192.png">
  <link rel="mask-icon" href="/BLOG/icons/safari-pinned-tab.svg" color="#3eaf7c">
  <meta name="msapplication-TileImage" content="/icons/192.png">
  <meta name="msapplication-TileColor" content="#3F51B5">
    
    <link rel="preload" href="/BLOG/assets/css/42.styles.90045bd1.css" as="style"><link rel="preload" href="/BLOG/assets/js/app.1a725be8.js" as="script"><link rel="preload" href="/BLOG/assets/js/24.ac5f7b41.js" as="script"><link rel="prefetch" href="/BLOG/assets/js/7.88ba0bb7.js"><link rel="prefetch" href="/BLOG/assets/js/0.d3e592bd.js"><link rel="prefetch" href="/BLOG/assets/js/1.39b9c99c.js"><link rel="prefetch" href="/BLOG/assets/js/2.68dc10c9.js"><link rel="prefetch" href="/BLOG/assets/js/3.dfebdd5e.js"><link rel="prefetch" href="/BLOG/assets/js/4.ea97a821.js"><link rel="prefetch" href="/BLOG/assets/js/5.d8c2ecbf.js"><link rel="prefetch" href="/BLOG/assets/js/6.e51cd79c.js"><link rel="prefetch" href="/BLOG/assets/js/8.d9eebc06.js"><link rel="prefetch" href="/BLOG/assets/js/9.1a541d13.js"><link rel="prefetch" href="/BLOG/assets/js/10.4ec9ca67.js"><link rel="prefetch" href="/BLOG/assets/js/11.02558377.js"><link rel="prefetch" href="/BLOG/assets/js/12.d0e2086f.js"><link rel="prefetch" href="/BLOG/assets/js/13.5af02ddd.js"><link rel="prefetch" href="/BLOG/assets/js/14.5d9fcbf2.js"><link rel="prefetch" href="/BLOG/assets/js/15.ca0178b2.js"><link rel="prefetch" href="/BLOG/assets/js/16.cd99d056.js"><link rel="prefetch" href="/BLOG/assets/js/17.56f11c1d.js"><link rel="prefetch" href="/BLOG/assets/js/18.21837cc7.js"><link rel="prefetch" href="/BLOG/assets/js/19.73335fea.js"><link rel="prefetch" href="/BLOG/assets/js/20.1632ab79.js"><link rel="prefetch" href="/BLOG/assets/js/21.43175244.js"><link rel="prefetch" href="/BLOG/assets/js/22.5b7c0cca.js"><link rel="prefetch" href="/BLOG/assets/js/23.e624ba97.js"><link rel="prefetch" href="/BLOG/assets/js/25.6934a11d.js"><link rel="prefetch" href="/BLOG/assets/js/26.407b2583.js"><link rel="prefetch" href="/BLOG/assets/js/27.7449d673.js"><link rel="prefetch" href="/BLOG/assets/js/28.52e25437.js"><link rel="prefetch" href="/BLOG/assets/js/29.fba21f3a.js"><link rel="prefetch" href="/BLOG/assets/js/30.2cd6d3e2.js"><link rel="prefetch" href="/BLOG/assets/js/31.0b0a749f.js"><link rel="prefetch" href="/BLOG/assets/js/32.92134487.js"><link rel="prefetch" href="/BLOG/assets/js/33.ad2b89cc.js"><link rel="prefetch" href="/BLOG/assets/js/34.9b22334e.js"><link rel="prefetch" href="/BLOG/assets/js/35.825f3d75.js"><link rel="prefetch" href="/BLOG/assets/js/36.cc3da84c.js"><link rel="prefetch" href="/BLOG/assets/js/37.8f339f62.js"><link rel="prefetch" href="/BLOG/assets/js/38.5674618f.js"><link rel="prefetch" href="/BLOG/assets/js/39.180f0d85.js"><link rel="prefetch" href="/BLOG/assets/js/40.275f26e3.js"><link rel="prefetch" href="/BLOG/assets/js/41.ce0f5927.js">
    <link rel="stylesheet" href="/BLOG/assets/css/42.styles.90045bd1.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div data-app="true" id="app" class="application theme--light"><div class="application--wrap"><div class="v-progress-linear blog-progress" style="height:3px;display:none;"><div class="v-progress-linear__background accent" style="height:3px;opacity:0.4;width:100%;"></div><div class="v-progress-linear__bar"><!----><div class="v-progress-linear__bar__determinate accent" style="width:0%;"></div></div></div><aside class="v-navigation-drawer v-navigation-drawer--close v-navigation-drawer--fixed v-navigation-drawer--is-mobile" style="height:100%;margin-top:0px;max-height:calc(100% - 0px);transform:translateX(-240px);width:240px;"><div><div class="aside-brand-wrap"><div class="aside-brand"><a href="/BLOG/" class="aside-avatar elevation-2 router-link-active"><img src="/BLOG/face.png" alt="avatar"></a><hgroup class="mt-3 variant-hide"><div class="subheading white--text">訾绍飞</div><a href="mailto:zishaofei221@gmail.com" title="zishaofei221@gmail.com" class="aside-mail primary--text text--lighten-5">zishaofei221@gmail.com</a></hgroup></div></div><hr class="v-divider theme--dark"><div class="v-list nav-list"><div class="secondary--text"><a href="/BLOG/" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-home"></i></div></div><div class="v-list__tile__content">首页</div></a></div><div class="secondary--text"><a href="/BLOG/tags" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-tag"></i></div></div><div class="v-list__tile__content">标签</div></a></div><div class="secondary--text"><a href="https://github.com/ShaofeiZi" target="_blank" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fab fa-github"></i></div></div><div class="v-list__tile__content">Github</div></a></div><div class="secondary--text"><a href="/BLOG/about" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-user-secret"></i></div></div><div class="v-list__tile__content">About</div></a></div></div></div><div class="v-navigation-drawer__border"></div></aside><nav class="blog-toolbar v-toolbar v-toolbar--fixed theme--dark primary" style="margin-top:0px;padding-right:0px;padding-left:0px;transform:translateY(0px);"><div class="v-toolbar__content" style="height:56px;"><button type="button" class="v-btn v-btn--icon"><div class="v-btn__content"><i class="fa fa-bars"></i></div></button><div class="v-toolbar__title">10 Observable Operator - combineLatest, withLatestFrom, zip</div><div class="spacer"></div><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><div class="v-menu" style="display:none;"><div class="v-menu__activator"><button type="button" class="v-btn v-btn--icon"><div class="v-btn__content"><i class="fa fa-share-alt"></i></div></button></div><div class="v-menu__content" style="max-height:auto;min-width:0px;max-width:auto;top:12px;left:0px;transform-origin:top right;z-index:0;display:none;"><div class="v-list"><div class="secondary--text"><a class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-lg fa-copy"></i></div></div><div class="v-list__tile__title">复制链接</div></a></div></div><input type="text" tabindex="-1" aria-hidden="true" value="" class="fake-hide"></div></div></div></nav><main class="v-content" style="padding-top:56px;padding-right:0px;padding-bottom:0px;padding-left:0px;"><div class="v-content__wrap"><div class="container blog-container grid-list-xl align-center"><div class="layout row wrap"><div class="flex mb-3 xs12"><article class="v-card elevation-16 post-card" style="height:undefined;"><div class="v-card__title"><div class="flex xs12"><h2 class="display-1 mb-3">10 Observable Operator - combineLatest, withLatestFrom, zip</h2><div class="post-meta"><time datetime="2018-04-29T12:16:02.000Z" class="secondary--text post-time">2018年04月29日</time></div></div></div><div class="v-card__text pt-0 pb-0"><div class="flex xs12"><div class="content custom"><h1 id="_30-天精通-rxjs-10-：-observable-operator-combinelatest-withlatestfrom-zip"><a href="#_30-天精通-rxjs-10-：-observable-operator-combinelatest-withlatestfrom-zip" aria-hidden="true" class="header-anchor">#</a> 30 天精通 RxJS (10)： Observable Operator - combineLatest, withLatestFrom, zip</h1><blockquote><p>非同步最难的地方在于，当有多个非同步行为同时触发且相互依赖，这时候我们要处理的逻辑跟状态就会变得极其复杂，甚至程序很可能会在完成的一两天后就成了 Legacy Code（遗留代码）。</p></blockquote><p>昨天我们最后讲到了 <code>merge</code> 的用法，它的逻辑就像是 OR(||)一样，可以把多个 observable 合并且同时处理，当其中任合一个 observable 送出元素时，我们都做相同的处理。</p><p>今天我们要讲的三个 operators 则像是 AND(&amp;&amp;) 逻辑，它们都是在多个元素送进来时，只输出一个新元素，但各自的行为上仍有差异，需要读者花点时间思考，建议在头脑清醒时阅读本篇文章。</p><h2 id="operators"><a href="#operators" aria-hidden="true" class="header-anchor">#</a> Operators</h2><h3 id="combinelatest"><a href="#combinelatest" aria-hidden="true" class="header-anchor">#</a> combineLatest</h3><p>首先我们要介绍的是 combineLatest，它会取得各个 observable 最后送出的值，再输出成一个值，我们直接看示例会比较好解释。</p><pre class="language-javascript"><code><span class="token keyword">var</span> source <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> newest <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> example <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">combineLatest</span><span class="token punctuation">(</span>newest<span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> x <span class="token operator">+</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span>

example<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    next<span class="token punctuation">:</span> <span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    error<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error: '</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    complete<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 0</span>
<span class="token comment">// 1</span>
<span class="token comment">// 2</span>
<span class="token comment">// 3</span>
<span class="token comment">// 4</span>
<span class="token comment">// 5</span>
<span class="token comment">// 6</span>
<span class="token comment">// 7</span>
<span class="token comment">// complete</span>

</code></pre><p><a href="https://jsbin.com/posutey/1/edit?js,console" target="_blank" rel="noopener noreferrer">JSBin</a> | <a href="https://jsfiddle.net/s6323859/55edtqpk/" target="_blank" rel="noopener noreferrer">JSFiddle</a></p><p>大家第一次看到这个 output 应该都会很困惑，我们直接来看 Marble Diagram 吧！</p><pre class="language-javascript"><code>source <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token operator">--</span><span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token number">2</span><span class="token operator">|</span>
newest <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token number">1</span><span class="token operator">--</span><span class="token number">2</span><span class="token operator">--</span><span class="token number">3</span><span class="token operator">--</span><span class="token number">4</span><span class="token operator">--</span><span class="token number">5</span><span class="token operator">|</span>

    <span class="token function">combineLatest</span><span class="token punctuation">(</span>newest<span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> x <span class="token operator">+</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span>

example<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token number">01</span><span class="token operator">--</span><span class="token number">23</span><span class="token operator">-</span><span class="token number">4</span><span class="token operator">--</span><span class="token punctuation">(</span><span class="token number">56</span><span class="token punctuation">)</span><span class="token operator">--</span><span class="token number">7</span><span class="token operator">|</span>

</code></pre><p>首先 <code>combineLatest</code> 可以接收多个 observable，最后一个参数是 callback function，这个 callback function 接收的参数数量跟合并的 observable 数量相同，依照示例来说，因为我们这里合并了两个 observable 所以后面的 callback function 就接收 x, y 两个参数，x 会接收从 source 发送出来的值，y 会接收从 newest 发送出来的值。</p><p>最后一个重点就是一定会等两个 observable 都<strong>曾有送值</strong>出来才会呼叫我们传入的 callback，所以这段程式是这样运行的</p><ul><li>newest 送出了 <code>0</code>，但此时 source 并没有送出过任何值，所以不会执行 callback</li><li>source 送出了 <code>0</code>，此时 newest 最后一次送出的值为 <code>0</code>，把这两个数传入 callback 得到 <code>0</code>。</li><li>newest 送出了 <code>1</code>，此时 source 最后一次送出的值为 <code>0</code>，把这两个数传入 callback 得到 <code>1</code>。</li><li>newest 送出了 <code>2</code>，此时 source 最后一次送出的值为 <code>0</code>，把这两个数传入 callback 得到 <code>2</code>。</li><li>source 送出了 <code>1</code>，此时 newest 最后一次送出的值为 <code>2</code>，把这两个数传入 callback 得到 <code>3</code>。</li><li>newest 送出了 <code>3</code>，此时 source 最后一次送出的值为 <code>1</code>，把这两个数传入 callback 得到 <code>4</code>。</li><li>source 送出了 <code>2</code>，此时 newest 最后一次送出的值为 <code>3</code>，把这两个数传入 callback 得到 <code>5</code>。</li><li>source 结束，但 newest 还没结束，所以 example 还不会结束。</li><li>newest 送出了 <code>4</code>，此时 source 最后一次送出的值为 <code>2</code>，把这两个数传入 callback 得到 <code>6</code>。</li><li>newest 送出了 <code>5</code>，此时 source 最后一次送出的值为 <code>2</code>，把这两个数传入 callback 得到 <code>7</code>。</li><li>newest 结束，因为 source 也结束了，所以 example 结束。</li></ul><p>不管是 source 还是 newest 送出值来，只要另一方曾有送出过值(有最后的值)，就会执行 callback 并送出新的值，这就是 combineLatest。</p><p>combineLatest 很常用在运算多个因子的结果，例如最常见的 BMI 计算，我们身高变动时就拿上一次的体重计算新的 BMI，当体重变动时则拿上一次的身高计算 BMI，这就很适合用 combineLatest 来处理！</p><h3 id="zip"><a href="#zip" aria-hidden="true" class="header-anchor">#</a> zip</h3><p>在讲 withLatestFrom 之前，先让我们先来看一下 zip 是怎么运行的，zip 会取每个 observable 相同顺位的元素并传入 callback，也就是说每个 observable 的第 n 个元素会一起被传入 callback，这里我们同样直接用示例讲解会比较清楚</p><pre class="language-javascript"><code><span class="token keyword">var</span> source <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> newest <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> example <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">zip</span><span class="token punctuation">(</span>newest<span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> x <span class="token operator">+</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span>

example<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    next<span class="token punctuation">:</span> <span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    error<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error: '</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    complete<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 0</span>
<span class="token comment">// 2</span>
<span class="token comment">// 4</span>
<span class="token comment">// complete</span>

</code></pre><p><a href="https://jsbin.com/posutey/2/edit?js,console" target="_blank" rel="noopener noreferrer">JSBin</a> | <a href="https://jsfiddle.net/s6323859/55edtqpk/1/" target="_blank" rel="noopener noreferrer">JSFiddle</a></p><p>Marble Diagram 长这样</p><pre class="language-javascript"><code>source <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token operator">--</span><span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token number">2</span><span class="token operator">|</span>
newest <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token number">1</span><span class="token operator">--</span><span class="token number">2</span><span class="token operator">--</span><span class="token number">3</span><span class="token operator">--</span><span class="token number">4</span><span class="token operator">--</span><span class="token number">5</span><span class="token operator">|</span>
    <span class="token function">zip</span><span class="token punctuation">(</span>newest<span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> x <span class="token operator">+</span> y<span class="token punctuation">)</span>
example<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token operator">--</span><span class="token number">2</span><span class="token operator">--</span><span class="token operator">--</span><span class="token number">4</span><span class="token operator">|</span>

</code></pre><p>以我们的示例来说，zip 会等到 source 跟 newest <strong>都送出了第一个元素</strong>，再传入 callback，下次则等到 source 跟 newest <strong>都送出了第二个元素</strong>再一起传入 callback，所以运行的步骤如下：</p><ul><li>newest 送出了<strong>第一个</strong>值 <code>0</code>，但此时 source 并没有送出<strong>第一个</strong>值，所以不会执行 callback。</li><li>source 送出了<strong>第一个</strong>值 <code>0</code>，newest 之前送出的<strong>第一个</strong>值为 <code>0</code>，把这两个数传入 callback 得到 <code>0</code>。</li><li>newest 送出了<strong>第二个</strong>值 <code>1</code>，但此时 source 并没有送出<strong>第二个</strong>值，所以不会执行 callback。</li><li>newest 送出了<strong>第三个</strong>值 <code>2</code>，但此时 source 并没有送出<strong>第三个</strong>值，所以不会执行 callback。</li><li>source 送出了<strong>第二个</strong>值 <code>1</code>，newest 之前送出的<strong>第二个</strong>值为 <code>1</code>，把这两个数传入 callback 得到 <code>2</code>。</li><li>newest 送出了<strong>第四个</strong>值 <code>3</code>，但此时 source 并没有送出<strong>第四个</strong>值，所以不会执行 callback。</li><li>source 送出了<strong>第三个</strong>值 <code>2</code>，newest 之前送出的<strong>第三个</strong>值为 <code>2</code>，把这两个数传入 callback 得到 <code>4</code>。</li><li>source 结束 example 就直接结束，因为 source 跟 newest 不会再有对应顺位的值</li></ul><p>zip 会把各个 observable 相同顺位送出的值传入 callback，这很常拿来做 demo 使用，比如我们想要间隔 100ms 送出 'h', 'e', 'l', 'l', 'o'，就可以这么做</p><pre class="language-javascript"><code><span class="token keyword">var</span> source <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token keyword">from</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> source2 <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> example <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">zip</span><span class="token punctuation">(</span>source2<span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> x<span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre><p>这里的 Marble Diagram 就很简单</p><pre class="language-javascript"><code>source <span class="token punctuation">:</span> <span class="token punctuation">(</span>hello<span class="token punctuation">)</span><span class="token operator">|</span>
source2<span class="token punctuation">:</span> <span class="token operator">-</span><span class="token number">0</span><span class="token operator">-</span><span class="token number">1</span><span class="token operator">-</span><span class="token number">2</span><span class="token operator">-</span><span class="token number">3</span><span class="token operator">-</span><span class="token number">4</span><span class="token operator">-</span><span class="token operator">...</span>
        <span class="token function">zip</span><span class="token punctuation">(</span>source2<span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> x<span class="token punctuation">)</span>
example<span class="token punctuation">:</span> <span class="token operator">-</span>h<span class="token operator">-</span>e<span class="token operator">-</span>l<span class="token operator">-</span>l<span class="token operator">-</span>o<span class="token operator">|</span>

</code></pre><p>这里我们利用 zip 来达到原本只能同步送出的资料变成了非同步的，很适合用在建立示范用的资料。</p><blockquote><p>建议大家平常没事不要乱用 zip，除非真的需要。因为 zip 必须 cache 住还没处理的元素，当我们两个 observable 一个很快一个很慢时，就会 cache 非常多的元素，等待比较慢的那个 observable。这很有可能造成内存相关的问题！</p></blockquote><h3 id="withlatestfrom"><a href="#withlatestfrom" aria-hidden="true" class="header-anchor">#</a> withLatestFrom</h3><p>withLatestFrom 运行方式跟 combineLatest 有点像，只是他有主从的关系，只有在主要的 observable 送出新的值时，才会执行 callback，附随的 observable 只是在背景下运行。让我们看一个例子</p><pre class="language-javascript"><code><span class="token keyword">var</span> main <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token keyword">from</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">zip</span><span class="token punctuation">(</span>Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> some <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token keyword">from</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">zip</span><span class="token punctuation">(</span>Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> x<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> example <span class="token operator">=</span> main<span class="token punctuation">.</span><span class="token function">withLatestFrom</span><span class="token punctuation">(</span>some<span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> y <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">?</span> x<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> x<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

example<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    next<span class="token punctuation">:</span> <span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    error<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error: '</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    complete<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre><p><a href="https://jsbin.com/posutey/6/edit?js,console" target="_blank" rel="noopener noreferrer">JSBin</a> | <a href="https://jsfiddle.net/s6323859/55edtqpk/2/" target="_blank" rel="noopener noreferrer">JSFiddle</a></p><p>先看一下 Marble Diagram</p><pre class="language-javascript"><code>main   <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span>h<span class="token operator">--</span><span class="token operator">--</span>e<span class="token operator">--</span><span class="token operator">--</span>l<span class="token operator">--</span><span class="token operator">--</span>l<span class="token operator">--</span><span class="token operator">--</span>o<span class="token operator">|</span>
some   <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token number">1</span><span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token number">1</span><span class="token operator">|</span>

<span class="token function">withLatestFrom</span><span class="token punctuation">(</span>some<span class="token punctuation">,</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token operator">=&gt;</span>  y <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">?</span> x<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> x<span class="token punctuation">)</span><span class="token punctuation">;</span>

example<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span>h<span class="token operator">--</span><span class="token operator">--</span>e<span class="token operator">--</span><span class="token operator">--</span>l<span class="token operator">--</span><span class="token operator">--</span><span class="token constant">L</span><span class="token operator">--</span><span class="token operator">--</span><span class="token constant">O</span><span class="token operator">|</span>

</code></pre><p>withLatestFrom 会在 main 送出值的时候执行 callback，但请注意如果 main 送出值时 some 之前没有送出过任何值 callback 仍然不会执行！</p><p>这里我们在 main 送出值时，去判断 some 最后一次送的值是不是 1 来决定是否要切换大小写，执行步骤如下</p><ul><li>main 送出了 <code>h</code>，此时 some 上一次送出的值为 <code>0</code>，把这两个参数传入 callback 得到 <code>h</code>。</li><li>main 送出了 <code>e</code>，此时 some 上一次送出的值为 <code>0</code>，把这两个参数传入 callback 得到 <code>e</code>。</li><li>main 送出了 <code>l</code>，此时 some 上一次送出的值为 <code>0</code>，把这两个参数传入 callback 得到 <code>l</code>。</li><li>main 送出了 <code>l</code>，此时 some 上一次送出的值为 <code>1</code>，把这两个参数传入 callback 得到 <code>L</code>。</li><li>main 送出了 <code>o</code>，此时 some 上一次送出的值为 <code>1</code>，把这两个参数传入 callback 得到 <code>O</code>。</li></ul><p>withLatestFrom 很常用在一些 checkbox 型的功能，例如说一个编辑器，我们开启粗体后，打出来的字就都要变粗体，粗体就像是 some observable，而我们打字就是 main observable。</p><h2 id="今日小结"><a href="#今日小结" aria-hidden="true" class="header-anchor">#</a> 今日小结</h2><p>今天介绍了三个合并用的 operators，这三个 operators 的 callback 都会依照合并的 observable 数量来传入参数，如果我们合并了三个 observable，callback 就会有三个参数，而不管合并几个 observable 都会只会回传一个值。</p><p>这几个 operators 需要花比较多的时间思考，读者们不用硬记他的运行行为，只要稍微记得有这些 operators 可以用就可以了。等到真的要用时，再重新回来看他们的运行方式做选择。</p><p>不知道读者们今天有没有收获呢？ 如果有任何问题，欢迎在下方留言给我，谢谢！</p></div></div></div><div class="v-card__actions"><div class="flex xs12"><a href="/BLOG/tags/RXJS"><span tabindex="0" class="v-chip capitalize chip-tag v-chip--label v-chip--small"><span class="v-chip__content">RXJS</span></span></a></div></div></article></div><div class="flex text-xs-left xs6"><a href="/BLOG/posts/rxjs11.html" class="post-nav v-btn v-btn--flat v-btn--router"><div class="v-btn__content"><div class="grey--text"><i class="fa mr-1 fa-chevron-left"></i>Prev</div><div class="title mt-1 primary--text hidden-xs-only">11 真实示例 - 完整拖拽应用</div></div></a></div><div class="flex text-xs-right xs6"><a href="/BLOG/posts/rxjs09.html" class="post-nav v-btn v-btn--flat v-btn--router"><div class="v-btn__content"><div class="grey--text">Next
          <i class="fa ml-1 fa-chevron-right"></i></div><div class="title mt-1 primary--text hidden-xs-only">09 Observable Operator - skip, takeLast, last, concat, startWith, merge</div></div></a></div><div class="flex mt-3 xs12"><div class="v-card" style="height:undefined;"><div class="v-card__title"><span class="headline">Comment</span></div></div></div></div></div><footer class="v-footer blog-footer darken-1 mt-3 theme--dark" style="height:auto;"><div class="primary--text text--lighten-4 text-xs-center py-3 v-card v-card--flat v-card--tile primary" style="height:undefined;"><div class="v-card__text pb-0">博客内容遵循 <a rel="license noopener noreferrer" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" target="_blank">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></div><div class="v-card__text pt-0 mt-1"><span>訾绍飞 © 2015 - 2018</span><span><!---->
        Power by
        <a href="https://vuepress.vuejs.org" target="_blank" rel="noopener noreferrer">VuePress</a> Theme
        <a href="https://github.com/ShaofeiZi/BLOG" target="_blank" rel="noopener noreferrer">indigo</a></span></div></div></footer></div></main><button type="button" class="v-btn v-btn--bottom v-btn--floating v-btn--fixed v-btn--right accent" style="display:none;"><div class="v-btn__content"><i class="fa fa-lg fa-chevron-up"></i></div></button></div></div></div>
    <script src="/BLOG/assets/js/24.ac5f7b41.js" defer></script><script src="/BLOG/assets/js/app.1a725be8.js" defer></script>
  </body>
</html>
